﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;

namespace Amie
{
    public partial class FrmPreReqs : Form
    {
        private PreReqResults preReqTest;
        private ProductInfo _info;
        private List<PreReqResults.CheckResult> testResults;

        public FrmPreReqs()
        {
            InitializeComponent();
        }

        private void FrmPreReqs_Shown(object sender, EventArgs e)
        {
            Init();
        }

        public void Init()
        {
            var pm = new ProductManager();
            _info = pm.GetProductFromConfig();
            preReqTest = new PreReqResults(_info);

            testResults = preReqTest.PerformTests();

            if (!HasInstalledConnectionString())
            {
                var conStrForm = new FrmConStr(_info);
                if (conStrForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                {
                    WriteConnectionStringRequired();
                    return;
                }
                //~The connection string is set in the form... if they press ok or test or both.  I don't really like this becuase it's not clear.  Global variable crap that get sticky... 
            }

            WriteHtmlDocument(testResults);
        }

        private bool HasInstalledConnectionString()
        {
            bool isGood = _info.ConnectionString != null && !string.IsNullOrEmpty(_info.ConnectionString.ConnectionString);
            return isGood;
        }

        /// <summary>
        /// Checks the prereq and version information. Returns false if everything checks out.  
        /// </summary>
        private bool PrereqTestsPass
        {
            get
            {
                if (testResults == null) return false;

                foreach (var item in testResults)
                {
                    if (!item.Pass) return false;
                }

                return true;
            }
        }

        private void WriteConnectionStringRequired()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(Header());
            sb.Append("<h1>Connection to the database was not found</h1>");
            sb.Append("<h4>Press the Re-Test button to enter the connection string to the database.</h4>");
            sb.Append("The database needs to be created before the installer can be ran.  Please create the database then come back and press the Re-Test button and enter the connection string details.");
            
            sb.Append(Footer());

            browser.DocumentText = sb.ToString();
        }

        private void WriteHtmlDocument(List<PreReqResults.CheckResult> results)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(Header());
            string updateRequired = _info.UpdateRequired ? "required" : "not required";
            sb.Append("<h1>Software update " + updateRequired + "</h1>");
            sb.Append("<h2>Server Prerequisite check</h2>");
            
            sb.Append("<p>This check ensures that the server has the following items installed and correctly configured.</p>");

            sb.Append(StartFeatureTable());

            foreach (var item in results)
            {
                sb.Append(AddTestResult(item));
            }

            sb.Append("</table>");

            sb.Append(BuildSoftwareInfoTable());
            
            sb.Append(Footer());

            browser.DocumentText = sb.ToString();
        }

        private string BuildSoftwareInfoTable()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<h2>Product Information</h2>");
            sb.Append("<p>This table shows the current version and update versions of the products being installed.</p>");

            string table = @"
                <table class='responstable'>
                    <tr>
                        <td><b>Product</b></td>
                        <td><b>Installed Version</b></td>
                        <td><b>Update Version</b></td>
                    </tr>";
            

            sb.Append(table);

            sb.Append(AddFeatureRow("Web - " + preReqTest.ProductInfo.WebApplicationName, preReqTest.ProductInfo.WebInstalledVersion.ToString(), preReqTest.ProductInfo.WebUpdateVersion.ToString()));
            sb.Append(AddFeatureRow("Service - " + preReqTest.ProductInfo.ServiceName, preReqTest.ProductInfo.ServiceInstalledVersion.ToString(), preReqTest.ProductInfo.ServiceUpdateVersion.ToString()));
            sb.Append(AddFeatureRow("Database - " + preReqTest.ProductInfo.ConnectionString.InitialCatalog, preReqTest.ProductInfo.DatabaseInstalledVersion.ToString(), preReqTest.ProductInfo.DatabaseUpdateVersion.ToString()));

            sb.Append("</table>");

            return sb.ToString();
        }

        private string StartFeatureTable()
        {
            string table = @"
                <table class='responstable'>
                    <tr>
                        <td><b>Service/Feature</b></td>
                        <td><b>Information</b></td>
                        <td><b>Pass/Fail</b></td>
                    </tr>";
            return table;
        }

        private string AddFeatureRow(string software, string installedVersion, string updateVersion)
        {
            var result = string.Format(
            @"<tr>
                <td>{0}</td>
                <td>{1}</td>
                <td>{2}</td>
            </tr>", software, installedVersion, updateVersion);

            return result;
        }

        private string Header()
        {
            string header = @"<!DOCTYPE html>
                        <html lang='en' xmlns='http://www.w3.org/1999/xhtml'>
                        <head>
                            <meta charset='utf-8' />
                            <title>Prereq Check</title>
                            <style>
                                .responstable {
                                    margin: 1em 0;
                                    width: 100%;
                                    overflow: hidden;
                                    background: #FFF;
                                    color: #024457;
                                    border-radius: 10px;
                                    border: 1px solid #167F92;
                                }
                                    .responstable tr {
                                        border: 1px solid #D9E4E6;
                                    }

                                        .responstable tr:nth-child(odd) {
                                            background-color: #EAF3F3;
                                        }

                                    .responstable th {
                                        display: none;
                                        border: 1px solid #FFF;
                                        background-color: #167F92;
                                        color: #FFF;
                                        padding: 1em;
                                    }

                                        .responstable th:first-child {
                                            display: table-cell;
                                            text-align: center;
                                        }

                                        .responstable th:nth-child(2) {
                                            display: table-cell;
                                        }

                                            .responstable th:nth-child(2) span {
                                                display: none;
                                            }

                                            .responstable th:nth-child(2):after {
                                                content: attr(data-th);
                                            }

                                @media (min-width: 480px) {
                                    .responstable th:nth-child(2) span {
                                        display: block;
                                    }

                                    .responstable th:nth-child(2):after {
                                        display: none;
                                    }
                                }

                                .responstable td {
                                    display: block;
                                    word-wrap: break-word;
                                    max-width: 7em;
                                }

                                    .responstable td:first-child {
                                        display: table-cell;
                                        text-align: center;
                                        border-right: 1px solid #D9E4E6;
                                    }

                                @media (min-width: 480px) {
                                    .responstable td {
                                        border: 1px solid #D9E4E6;
                                    }
                                }

                                .responstable th, .responstable td {
                                    text-align: left;
                                    margin: .5em 1em;
                                }

                                @media (min-width: 480px) {
                                    .responstable th, .responstable td {
                                        display: table-cell;
                                        padding: 1em;
                                    }
                                }

                                body {
                                    padding: 0 2em;
                                    font-family: Arial, sans-serif;
                                    color: #024457;
                                    background: #ffffff;
                                }

                                h1 {
                                    font-family: Verdana;
                                    font-weight: normal;
                                    color: #024457;
                                }

                                    h1 span {
                                        color: #167F92;
                                    }
                            </style>
                        </head>
                        <body>";
            return header;
        }

        private string Footer()
        {
            string footer = @"
                    </body>
                    </html>";
            return footer;
        }

        private string AddTestResult(PreReqResults.CheckResult checkResult)
        {
            var result = string.Format(
            @"<tr>
                <td>{0}</td>
                <td>{1}</td>
                <td>{2}</td>
            </tr>", checkResult.TestName, checkResult.TestInformation, checkResult.PassText);

            return result;
        }

        private void btnContinue_Click(object sender, EventArgs e)
        {

            if (!PrereqTestsPass)
            {
                string error = "";
                foreach (var item in testResults)
                {
                    if (item.Pass == false)
                    {
                        error += item.TestName + " failed. ";
                        error += item.TestInformation;
                    }
                }
                MessageBox.Show("Prerequisite check failed.  Installation will not continute!" + error, "Prerequisite check failed");
                return;
            }

            if (!_info.UpdateRequired)
            {
                if (MessageBox.Show("No update required.  Installation will not continute. \r\n Press Retry to force the installation.", "Update not required", MessageBoxButtons.RetryCancel) == System.Windows.Forms.DialogResult.Cancel)
                    return;
            }

            RunUpdate();
        }

        private void RunUpdate()
        {
            var appHelper = new ApplicationHelper(_info);
            try
            {
                var conStrForm = new FrmConStr(_info);
                if (conStrForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Logger.Info("INSTALL START: {0}--------------------------------------", DateTime.Now.ToString());
                    var result = appHelper.RunApplicationUpdates();
                    if (result.Success)
                    {
                        if (MessageBox.Show("Installation Complete!  Yep that's it.  Press okay to close this installer.  " + _info.WebApplicationName + " will be displayed in a browser on this server.", "Installation Complete", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
                        {
                            CloseInstallerAndOpenBrowser();
                        }
                    }
                    else
                    {
                        MessageBox.Show("Installation failed. " + result.Message + ". More detail in installation logs at " + Logger.logfilePath, "Installation Failed");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            finally
            {
                Logger.Info("INSTALL END: {0}--------------------------------------", DateTime.Now.ToString());
            }
        }

        private void CloseInstallerAndOpenBrowser()
        {
            System.Diagnostics.Process.Start("http://localhost/" + _info.WebApplicationName);
            ExitApplication();
        }

        private void btnReTest_Click(object sender, EventArgs e)
        {
            Init();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            ExitApplication();
        }

        private void ExitApplication()
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.Close();
            Application.Exit();
        }

        private void btnProductInfo_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            var frmDetails = new FrmProperties(_info);
            frmDetails.Show();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExitApplication();
        }

        private void dBOnlyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RunDatabaseUpdateOnly();
        }

        private void RunDatabaseUpdateOnly()
        {
            if (MessageBox.Show("You are about to update your database. Are you sure?", "Are you sure?") != System.Windows.Forms.DialogResult.OK) return;
            
            var appHelper = new ApplicationHelper(_info);
            try
            {
                var conStrForm = new FrmConStr(_info);
                if (conStrForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Logger.Info("Database Update Only START: {0}--------------------------------------", DateTime.Now.ToString());
                    var result = appHelper.UpdateDatabase();
                    if (result.Success)
                    {
                        if (MessageBox.Show("Database Updatge Complete!  Yep that's it.  Press okay to close this installer.", "Installation Complete", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
                        {
                            ExitApplication();
                        }
                    }
                    else
                    {
                        MessageBox.Show("Database update failed. " + result.Message + ". More detail in installation logs at " + Logger.logfilePath, "Database update failed");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            finally
            {
                Logger.Info("Database Update Only END: {0}--------------------------------------", DateTime.Now.ToString());
            }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {

            if (keyData == Keys.F3)
            {
                RunDatabaseUpdateOnly();
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

    }
}
